/*
 * Copyright DataStax, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.wsl.jvm.struct.bits


import com.gitee.wsl.lang.bits.AbstractBitSet
import com.gitee.wsl.lang.bits.DocIdSetIterator
import java.util.concurrent.atomic.AtomicLongArray

/**
 * A [AbstractBitSet] implementation that offers concurrent reads and writes through an [ ] as bit storage.
 *
 *
 * For now, only implements the minimum functionality required by BitSet
 * (in contrast to the extra methods in FixedBitSet).
 */
class AtomicFixedBitSet(numBits: Int) : AbstractBitSet() {
    private val storage: AtomicLongArray

    init {
        val numLongs = numBits + 63 ushr 6
        storage = AtomicLongArray(numLongs)
    }

    override fun length(): Int {
        return storage.length() shl 6
    }

    override fun set(i: Int) {
        val idx = index(i)
        val mask = mask(i)
        storage.getAndAccumulate(
            idx, mask
        ) { prev: Long, m: Long -> prev or m }
    }

    override operator fun get(i: Int): Boolean {
        if (i >= length()) {
            return false
        }
        val idx = index(i)
        val mask = mask(i)
        val value = storage[idx]
        return value and mask != 0L
    }

    override fun getAndSet(i: Int): Boolean {
        val idx = index(i)
        val mask = mask(i)
        val prev = storage.getAndAccumulate(
            idx, mask
        ) { p: Long, m: Long -> p or m }
        return prev and mask != 0L
    }

    override fun clear() {
        for (i in 0 until storage.length()) {
            storage[i] = 0L
        }
    }

    override fun clear(i: Int) {
        if (i >= length()) {
            return
        }
        val idx = index(i)
        val mask = mask(i)
        storage.getAndAccumulate(
            idx, mask
        ) { prev: Long, m: Long -> prev and m.inv() }
    }

    override fun clear(startIndex: Int, endIndex: Int) {
        if (endIndex <= startIndex) {
            return
        }
        val startIdx = index(startIndex)
        val endIdx = index(endIndex - 1)
        var startMask = -1L shl (startIndex and 63)
        var endMask = -1L ushr -(endIndex and 63)

        // Invert masks since we are clearing
        startMask = startMask.inv()
        endMask = endMask.inv()
        if (startIdx == endIdx) {
            storage.getAndAccumulate(
                startIdx, startMask or endMask
            ) { prev: Long, m: Long -> prev and m }
            return
        }
        storage.getAndAccumulate(
            startIdx, startMask
        ) { prev: Long, m: Long -> prev and m }
        for (i in startIdx + 1 until endIdx) {
            storage[i] = 0L
        }
        storage.getAndAccumulate(
            endIdx, endMask
        ) { prev: Long, m: Long -> prev and m }
    }

    override fun cardinality(): Int {
        var count = 0
        for (i in 0 until storage.length()) {
            count += java.lang.Long.bitCount(storage[i])
        }
        return count
    }

    override fun approximateCardinality(): Int {
        return cardinality()
    }

    override fun prevSetBit(index: Int): Int {
        assert(index >= 0 && index < length()) { "index=" + index + " length=" + length() }
        var i = index(index)
        val subIndex = index and 63 // index within the word
        var word = storage[i] shl 63 - subIndex // skip all the bits to the left of index
        if (word != 0L) {
            return (i shl 6) + subIndex - java.lang.Long.numberOfLeadingZeros(word)
        }
        while (--i >= 0) {
            word = storage[i]
            if (word != 0L) {
                return (i shl 6) + 63 - java.lang.Long.numberOfLeadingZeros(word)
            }
        }
        return -1
    }

    override fun nextSetBit(index: Int): Int {
        assert(index >= 0 && index < length()) { "index=" + index + ", length=" + length() }
        var i = index(index)
        if (i >= storage.length()) {
            return NO_MORE_DOCS
        }
        var word =
            storage[i] and (-1L shl (index and 63)) // Mask all the bits to the right of index
        while (true) {
            if (word != 0L) {
                return (i shl 6) + java.lang.Long.numberOfTrailingZeros(word)
            }
            if (++i >= storage.length()) {
                return NO_MORE_DOCS
            }
            word = storage[i]
        }
    }

    override fun clone(): AbstractBitSet {
        TODO("Not yet implemented")
    }

    override fun ramBytesUsed(): Long {
        /*val longSizeInBytes = java.lang.Long.BYTES
        val arrayOverhead = 16 // Estimated overhead of AtomicLongArray object in bytes
        val storageSize = storage.length().toLong() * longSizeInBytes + arrayOverhead
        return BASE_RAM_BYTES_USED + storageSize*/
        return 0
    }


    companion object {
        /*private val BASE_RAM_BYTES_USED: Long = RamUsageEstimator.shallowSizeOfInstance(
            AtomicFixedBitSet::class.java
        )*/

        private fun index(bit: Int): Int {
            return bit shr 6
        }

        private fun mask(bit: Int): Long {
            return 1L shl bit
        }
    }
}
